{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f04dd603-a2d1-48ce-8c17-9f1dba8de1ee",
   "metadata": {},
   "source": [
    "Chapter 10\n",
    "\n",
    "# 一元线性回归\n",
    "《线性代数》 | 鸢尾花书：数学不难"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccafb456-2453-4c82-8a65-b1963a370cb2",
   "metadata": {},
   "source": [
    "这段代码实现了**一元线性回归（Ordinary Least Squares, OLS）** 的完整过程，从数学角度，它展示了如何通过最小化误差平方和来拟合一条直线。\n",
    "\n",
    "---\n",
    "\n",
    "### 一、建模目标与模型形式\n",
    "\n",
    "我们假设数据集包含 $n$ 个样本点，每个样本点包括一个自变量 $x_i$ 和一个因变量 $y_i$，回归目标是拟合如下形式的线性函数：\n",
    "\n",
    "$$\n",
    "\\hat{y} = b_0 + b_1 x\n",
    "$$\n",
    "\n",
    "这个表达式也可以写成矩阵形式：\n",
    "\n",
    "$$\n",
    "\\hat{\\boldsymbol{y}} = X \\boldsymbol{b}\n",
    "$$\n",
    "\n",
    "其中：\n",
    "\n",
    "- $X \\in \\mathbb{R}^{n \\times 2}$ 是**设计矩阵**，每行是一个样本的输入特征，第一列为全1（对应截距项 $b_0$），第二列为自变量 $x$；\n",
    "- $\\boldsymbol{b} \\in \\mathbb{R}^{2 \\times 1}$ 是回归参数列向量，包含截距 $b_0$ 和斜率 $b_1$；\n",
    "- $\\hat{\\boldsymbol{y}}$ 是对观测值 $\\boldsymbol{y}$ 的预测值。\n",
    "\n",
    "---\n",
    "\n",
    "### 二、最小二乘解的推导\n",
    "\n",
    "最小二乘法的目标是最小化预测值和真实值之间的残差平方和：\n",
    "\n",
    "$$\n",
    "\\min_{\\boldsymbol{b}} \\|\\boldsymbol{y} - X \\boldsymbol{b}\\|_2^2\n",
    "$$\n",
    "\n",
    "通过求导并令导数为零，可得正规方程（normal equation）：\n",
    "\n",
    "$$\n",
    "X^\\top X \\boldsymbol{b} = X^\\top \\boldsymbol{y}\n",
    "$$\n",
    "\n",
    "从而得到回归系数的封闭解：\n",
    "\n",
    "$$\n",
    "\\boldsymbol{b} = (X^\\top X)^{-1} X^\\top \\boldsymbol{y}\n",
    "$$\n",
    "\n",
    "这就是代码中这句所实现的操作：\n",
    "\n",
    "```python\n",
    "b = np.linalg.inv(X.T @ X) @ X.T @ y\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 三、格拉姆矩阵与其逆\n",
    "\n",
    "表达式 $X^\\top X$ 是**格拉姆矩阵（Gram Matrix）**，在一元线性回归中，它是一个 $2 \\times 2$ 对称正定矩阵。它的形式为：\n",
    "\n",
    "$$\n",
    "X^\\top X = \n",
    "\\begin{bmatrix}\n",
    "n & \\sum x_i \\\\\n",
    "\\sum x_i & \\sum x_i^2\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "这个矩阵反映了输入特征之间的内积关系，其逆矩阵 $(X^\\top X)^{-1}$ 被用于求解最小二乘解。\n",
    "\n",
    "---\n",
    "\n",
    "### 四、预测与误差分析\n",
    "\n",
    "计算预测值的操作：\n",
    "\n",
    "$$\n",
    "\\hat{\\boldsymbol{y}} = X \\boldsymbol{b}\n",
    "$$\n",
    "\n",
    "用于训练数据的预测是：\n",
    "\n",
    "```python\n",
    "y_pred = X @ b\n",
    "```\n",
    "\n",
    "而对新的输入区间（如 0 到 10）生成预测曲线：\n",
    "\n",
    "```python\n",
    "y_array_pred = X_array @ b\n",
    "```\n",
    "\n",
    "其中 `X_array` 是将新输入值添加全1列后的新设计矩阵。\n",
    "\n",
    "接着计算训练集上的误差向量：\n",
    "\n",
    "$$\n",
    "\\boldsymbol{e} = \\boldsymbol{y} - \\hat{\\boldsymbol{y}}\n",
    "$$\n",
    "\n",
    "代码为：\n",
    "\n",
    "```python\n",
    "error = y - y_pred\n",
    "```\n",
    "\n",
    "误差的平方和：\n",
    "\n",
    "$$\n",
    "\\|\\boldsymbol{e}\\|_2^2 = \\boldsymbol{e}^\\top \\boldsymbol{e}\n",
    "$$\n",
    "\n",
    "这就是线性回归的损失函数（Residual Sum of Squares, RSS），也就是最小化的目标函数。\n",
    "\n",
    "---\n",
    "\n",
    "### 总结：\n",
    "\n",
    "这段代码实现了以下数学过程：\n",
    "\n",
    "1. 构造设计矩阵 $X$；\n",
    "2. 根据正规方程计算最小二乘解 $\\boldsymbol{b}$；\n",
    "3. 利用 $\\boldsymbol{b}$ 生成预测值 $\\hat{\\boldsymbol{y}}$；\n",
    "4. 计算误差向量 $\\boldsymbol{e} = \\boldsymbol{y} - \\hat{\\boldsymbol{y}}$；\n",
    "5. 计算误差的 $L^2$ 范数平方 $\\|\\boldsymbol{e}\\|_2^2$，用于评估拟合质量。\n",
    "\n",
    "需要的话，我可以接着画出这条回归线和原始数据点的图像。是否继续？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b10e2dd4-a360-422c-b3f2-9145284e6b34",
   "metadata": {},
   "source": [
    "## 初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d530bc5e-a5b5-41cf-92e4-461541be8fc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efcab4d0-b10e-4767-abbd-e4e4002fc2fe",
   "metadata": {},
   "source": [
    "## 数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fe901b32-f312-4a76-8a04-e5414c9adb89",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([1,2,3,5,6,7,8,9]).reshape(-1,1)   # 自变量 x\n",
    "y = np.array([3,1,4,6,5,8,7,8]).reshape(-1,1)   # 因变量 y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "7cf1c88f-2a8a-4383-98df-be1ea1b311df",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 构造设计矩阵，增加全1列向量\n",
    "X = np.column_stack((np.ones_like(x), x))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c85ae8d-c6be-4e86-a658-060b73ec6ced",
   "metadata": {},
   "source": [
    "## 计算参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b0c66c95-c5b5-4b5b-a83c-90abf6b0f041",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.26751592],\n",
       "       [0.77707006]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.linalg.inv(X.T @ X) @ X.T @ y\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c154f5ea-0d03-4835-9ff4-b08ef70ae13c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  8,  41],\n",
       "       [ 41, 269]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 格拉姆矩阵\n",
    "X.T @ X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "57f86420-21a2-4310-855e-cd427613255b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.57112527, -0.08704883],\n",
       "       [-0.08704883,  0.01698514]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 格拉姆矩阵的逆\n",
    "np.linalg.inv(X.T @ X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "247f789c-6dd6-42e7-9ef4-7afee9277169",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 42],\n",
       "       [261]])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.T @ y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c6a7431-1c23-47c2-9f07-895bddf00d75",
   "metadata": {},
   "source": [
    "## 计算预测值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "46a9fb1f-f66f-4795-8161-3bd7229e36c7",
   "metadata": {},
   "outputs": [],
   "source": [
    "x_array = np.linspace(0,10)\n",
    "X_array = np.column_stack((np.ones_like(x_array), x_array))\n",
    "\n",
    "y_array_pred = X_array @ b\n",
    "y_pred = X @ b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80d7395d-2da7-43cd-a3c7-74f2d4d17362",
   "metadata": {},
   "source": [
    "## 误差向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86f51b77-13a8-4a28-89a5-89ffc76145b4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.95541401],\n",
       "       [-1.82165605],\n",
       "       [ 0.40127389],\n",
       "       [ 0.84713376],\n",
       "       [-0.92993631],\n",
       "       [ 1.29299363],\n",
       "       [-0.48407643],\n",
       "       [-0.2611465 ]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "error = y - y_pred\n",
    "error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "0cb11d77-c59c-43b8-a7f1-f88192dd425d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[7.94904459]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 误差向量的L2范数的平方\n",
    "error.T @ error"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "caa7e150-6d25-4b39-b5f4-b634d9a76137",
   "metadata": {},
   "source": [
    "## 可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "c075e159-2d17-4be0-a98e-47053781e78b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(5,5))\n",
    "\n",
    "# 绘制样本数据\n",
    "ax.scatter(x, y, marker = 'x', color = 'b')\n",
    "\n",
    "# 绘制回归直线\n",
    "ax.plot(x_array, y_array_pred, color='r')\n",
    "\n",
    "# 绘制预测值\n",
    "ax.scatter(x, y_pred, marker = 'x', color='r')\n",
    "\n",
    "# 绘制误差\n",
    "ax.plot(([i for i in x.squeeze()], [i for i in x.squeeze()]),\n",
    "        ([j for j in y_pred.squeeze()], [j for j in y.squeeze()]),\n",
    "         c='#FFC000', alpha = 0.5)\n",
    "\n",
    "# 装饰\n",
    "ax.set_xlabel('x')\n",
    "ax.set_ylabel('y')\n",
    "ax.set_xlim(0,10)\n",
    "ax.set_ylim(0,10)\n",
    "ax.set_xticks(np.arange(11))\n",
    "ax.set_yticks(np.arange(11))\n",
    "ax.grid(True, c = '0.8')\n",
    "ax.set_aspect('equal', 'box')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "070c3389-8048-43a3-baa7-6666009bce96",
   "metadata": {},
   "source": [
    "作者\t**生姜DrGinger**  \n",
    "脚本\t**生姜DrGinger**  \n",
    "视频\t**崔崔CuiCui**  \n",
    "开源资源\t[**GitHub**](https://github.com/Visualize-ML)  \n",
    "平台\t[**油管**](https://www.youtube.com/@DrGinger_Jiang)\t\t\n",
    "\t\t[**iris小课堂**](https://space.bilibili.com/3546865719052873)\t\t\n",
    "\t\t[**生姜DrGinger**](https://space.bilibili.com/513194466)  "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
